<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>跨标签页通信</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        html,body{
            position: relative;
            width: 100vw;
            height: 100vh;
            overflow: hidden;
        }
        body{
            background: #EDF2F7;
        }
        .box{
            display: block;
            position: absolute;
            width: 300px;
            height: 200px;
            border-radius: 8px;
            box-shadow: 0 10px 10px #353535;
            background: #fff;
            cursor: grab;
        }
        .init-btn{
            position: absolute;
            right: 10px;
            display: inline-block;
            margin: 10px;
            padding: 12px 16px;
            border: 1px solid #2196f3;
            border-radius: 8px;
            background: #fff;
            color:#2196f3;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
        }
        .init-btn:hover{
            border-color: #fff;
            background-color: #2196f3;
            color:#fff;
        }
    </style>
</head>
<body>
    <div class="box" style="left: 0; top: 0;"></div>
    <div class="init-btn">
        <span>初始化</span>
    </div>
</body>
<script>
let block = document.querySelector(".box");
let btn = document.querySelector(".init-btn");
let channel = new BroadcastChannel("Transfer");
let offsetX = 0;
let offsetY = 0;
function convertCoords(type,coords){
    let {x,y} = coords;
    let {screenLeft,screenTop} = window;
    switch(type){
        case 'p2s':
            // 屏幕坐标
            return {
                x: x + screenLeft + offsetX,
                y: y + screenTop + offsetY
            }
        case 's2p':
            // 页面坐标
            return {
                x: x - screenLeft - offsetX,
                y: y - screenTop - offsetY
            }
        default:
            console.error("转换失败，类型错误。");
            return {x:0,y:0}
    }
}
function handleAdjustOffset(data){
    console.log('[AdjustOffset]',data);
    offsetX = data.x;
    offsetY = data.y;
    if(btn){
        btn.remove();
    }
}
function handleUpdateCoords(data){
    let {x,y} = convertCoords('s2p',data);
    block.style.left = x + 'px';
    block.style.top = y + 'px';
}
function initElementCoords(){
    let elementW = block.clientWidth;
    let elementH = block.clientHeight;
    let windowW = window.innerWidth;
    let windowH = window.innerHeight;
    block.style.left = Math.round(windowW / 2 - elementW / 2) + 'px';
    block.style.top = Math.round(windowH / 2 - elementH / 2) + 'px';
}
function parseChannelMessage(event){
    let data = event.data;
    if(data && data.type){
        return data;
    }else{
        return {
            type: '',
            data: null
        };
    }
}
block.addEventListener('mousedown',function (downEvent){
    let elementCoords = convertCoords('p2s',{
        x: parseInt(block.style.left),
        y: parseInt(block.style.top)
    });
    let elementX = elementCoords.x;
    let elementY = elementCoords.y;
    let cursorX = downEvent.screenX;
    let cursorY = downEvent.screenY;
    let handleMove = function (moveEvent){
        let newX = elementX + (moveEvent.screenX - cursorX);
        let newY = elementY + (moveEvent.screenY - cursorY);
        let coords = {x : newX,y: newY};
        handleUpdateCoords(coords);
        channel.postMessage({
            type: 'UpdateCoords',
            data: coords
        })
    }
    let handleUp = function (){
        window.removeEventListener('mousemove',handleMove);
        window.removeEventListener('mouseup',handleUp);
    }
    window.addEventListener('mousemove',handleMove);
    window.addEventListener('mouseup',handleUp);
})
btn.addEventListener('click',function(ev){
    let {pageX,pageY,screenX,screenY} = ev;
    let offsetX = 0, offsetY = 0;
    let relativeX = screenX - window.screenLeft;
    let relativeY = screenY - window.screenTop;
    while(relativeX > pageX){
        offsetX++;
        relativeX--;
    };
    while(relativeY > pageY){
        offsetY++;
        relativeY--;
    };
    handleAdjustOffset({
        x: offsetX,
        y: offsetY
    });
    channel.postMessage({
        type: 'AdjustOffset',
        data: {x: offsetX, y: offsetY}
    });
    let coords = convertCoords('p2s',{
        x: parseInt(block.style.left),
        y: parseInt(block.style.top)
    });
    handleUpdateCoords(coords);
    channel.postMessage({
        type: 'UpdateCoords',
        data: coords
    });
})
channel.addEventListener('message',function (ev){
    let {data,type} = parseChannelMessage(ev);
    switch(type){
        case 'AdjustOffset':
            handleAdjustOffset(data);
            break;
        case 'UpdateCoords':
            handleUpdateCoords(data);
            break;
        default:
            break;
    }
})
initElementCoords();
</script>
</html>